<template>
  <div>
    <vue-draggable-next
      v-model="elements_"
      class="maker-display"
      v-bind="{ ...$attrs, ...to }"
      :tag="tag || 'div'"
      :component-data="componentData"
      :component="component"
      @change="onElement"
    >
      <slot
        :selected="selected"
        :select="(index) => onSelectElement(index)"
        :remove="(index) => onRemoveElement(index)"
        :update="(element, v) => update(element, v)"
      >
        <template v-for="(element, index) in elements_" :key="element.name">
          <slot
            name="item"
            :element="element"
            :index="index"
            :selected="selected"
            :model-value="value[element.name]"
            :select="() => onSelectElement(index)"
            :remove="() => onRemoveElement(index)"
            :update="(v) => update(element, v)"
          />
        </template>
      </slot>
    </vue-draggable-next>
    <teleport v-if="selected >= 0" to="#maker-item-config-panel">
      <epx-form v-model="ele" :fields="fields" size="small" :toolbar="false" />
    </teleport>
    <slot name="display"></slot>
  </div>
</template>

<script lang="ts" setup>
  import { VueDraggableNext } from 'vue-draggable-next';
  import EpxForm from '../form/EpxForm.vue';
  import { Field, SelectorOptions, Trigger } from '../form/form';
  import { Collection, commons as fs, Model } from './structure';
  import { Er, Row } from '../elementUI';
  import { computed, nextTick, onBeforeUnmount, ref } from 'vue';
  import { Panel } from './PropertyPanel';

  const props = defineProps<{
    /**
     * 现有的元素
     */
    elements?: Er[];
    /**
     * 配置项
     */
    collection: Collection;
    /**
     * 值
     */
    modelValue?: Row;

    /**
     * 和拖拽有关的配置
     */
    name?: string;

    /**
     * 和外包装有关的配置
     */
    tag?: string;
    component?: string;
    componentData?: Record<string, unknown>;

    /**
     * 绑定的 model
     */
    model?: Model;
  }>();

  const emit = defineEmits(['update:elements', 'update:modelValue']);

  const elements_ = computed<Er[]>({
    get: () => props.elements || [],
    set: (es) => emit('update:elements', es)
  });

  const value = computed<Row>({
    get: () => props.modelValue || {},
    set: (v) => emit('update:modelValue', v)
  });

  const update = (element: Er, v: unknown) => {
    value.value[element.name] = v;
  };

  /**
   * 被选中的元素的索引
   */
  const selected = ref(-1);

  /**
   * 当前被选中的元素
   */
  const ele = computed<Er>({
    get: () => elements_.value[selected.value],
    set: (e: Er, i = -1) => {
      if (i < 0) i = selected.value;
      if (i >= 0) elements_.value[i] = e;
    }
  });
  /**
   * 当前元素的属性项
   */
  const fields = ref<Field[]>([]);

  const to = computed(() => ({
    group: {
      // 拖曳分组
      name: props.name || 'drag',
      // 可拖出及效果
      pull: true,
      // 可拖入
      put: true
    },
    // 可拖曳排序
    sort: true
  }));

  const close = () => {
    selected.value = -1;
    fields.value = [];
  };
  // 开启时注册面板
  Panel.onClose(close);
  // 关闭注销面板
  onBeforeUnmount(() => Panel.close(close));

  const onRemoveElement = (index: number) => {
    if (selected.value === index) Panel.close();
    elements_.value.splice(index, 1);
    if (selected.value > index) selected.value -= 1;
  };

  const onSelectElement = (index: number) => {
    if (index === selected.value) {
      Panel.close();
      return;
    }

    Panel.close();

    // !!! 先打开，后赋值 !!!
    Panel.open();

    nextTick(() => {
      selected.value = index;

      // eslint-disable-next-line @typescript-eslint/ban-ts-comment
      // @ts-ignore
      const key: string = elements_.value[selected.value][props.collection.point];
      const fields_ = [
        ...(props.collection.before || []),
        ...(props.collection.structures[key] || []),
        ...(props.collection.after || [])
      ];

      // name 配置项
      if (props.model?.elements) {
        const options: SelectorOptions = props.model.elements.map((er) => ({
          label: er.label + '',
          value: er.name
        }));

        const trigger: Trigger['options'] = {};
        props.model.elements.forEach((er) => {
          trigger[er.name] = { label: er.label };
        });

        fields_.unshift({
          name: 'name',
          widget: 'select',
          label: '标识符',
          options,
          trigger: { options: trigger }
        });
      } else {
        fields_.unshift(fs.name);
      }

      /**
       * 处理复杂的field配置
       */
      fields.value = fields_.map((field) => field);
    });
  };

  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  const onElement = (event: any) => {
    if (event.added) {
      // 增加这里有点问题..,需要手动提交一次
      if (elements_.value.length == 1) emit('update:elements', elements_.value);
      // console.log(event);
      // console.log(elements_.value);
      Panel.close();
      onSelectElement(event.added.newIndex);
      return;
    }

    if (event.moved) {
      Panel.close();
      onSelectElement(event.moved.newIndex);
      return;
    }
  };
</script>

<script lang="ts">
  // 声明额外的选项
  // noinspection JSUnusedGlobalSymbols
  export default {
    inheritAttrs: false
  };
</script>
<style scoped>
  .maker-display {
    border: #67c23a 1px dashed;
    min-height: 100px;
    padding: 12px;
    border-radius: 4px;
  }
</style>
